package com.niiwoo.civet.account.service.local.check;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.niiwoo.civet.trade.dto.response.creditor.CreditorTransferConfirmOrderDetailDTO;
import com.niiwoo.civet.trade.dto.response.newRefund.RefundOrderDetailBizResponseDTO;
import com.niiwoo.civet.trade.service.creditor.CreditorTransferConfirmDubboService;
import com.niiwoo.civet.trade.service.newRefund.RefundOrderDetailBizDubboService;
import com.niiwoo.tripod.lanmao.enums.BusinessTypeEnum;
import com.alibaba.dubbo.config.annotation.Reference;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.dangdang.ddframe.rdb.sharding.api.HintManager;
import com.dangdang.ddframe.rdb.sharding.hint.HintManagerHolder;
import com.github.pagehelper.PageHelper;
import com.niiwoo.civet.account.dao.entity.AccountCheckingActivityOrder;
import com.niiwoo.civet.account.dao.entity.AccountCheckingException;
import com.niiwoo.civet.account.dao.entity.AccountCheckingFundTransferOrder;
import com.niiwoo.civet.account.dao.entity.AccountCheckingInvestOrder;
import com.niiwoo.civet.account.dao.entity.AccountCheckingTransOrder;
import com.niiwoo.civet.account.dao.entity.AccountCheckingTransStat;
import com.niiwoo.civet.account.dao.entity.AccountCheckingTransation;
import com.niiwoo.civet.account.dao.mapper.AccountCheckingActivityOrderMapper;
import com.niiwoo.civet.account.dao.mapper.AccountCheckingFundTransferOrderMapper;
import com.niiwoo.civet.account.dao.mapper.AccountCheckingInvestOrderMapper;
import com.niiwoo.civet.account.dao.mapper.AccountCheckingTransOrderMapper;
import com.niiwoo.civet.account.dao.mapper.AccountCheckingTransStatMapperExt;
import com.niiwoo.civet.account.dao.mapper.AccountCheckingTransationMapperExt;
import com.niiwoo.civet.account.service.local.check.job.api.CheckDetailService;
import com.niiwoo.civet.account.service.local.check.job.api.ParseService;
import com.niiwoo.civet.account.service.local.check.job.enums.BankBizTypeEnum;
import com.niiwoo.civet.account.service.local.check.job.enums.CheckExceptionStatusEnum;
import com.niiwoo.civet.account.service.local.check.job.enums.CheckResultEnum;
import com.niiwoo.civet.account.service.local.check.job.enums.HandleTypeEnum;
import com.niiwoo.civet.account.service.local.check.job.util.DateUtil;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class AccountCheckingTransationService
		implements ParseService<AccountCheckingTransation>, CheckDetailService<AccountCheckingTransation> {

	@Autowired
	private AccountCheckingTransationMapperExt accountCheckingTransationMapperExt;

	@Autowired
	private AccountCheckingTransOrderMapper accountCheckingTransOrderMapper;

	@Autowired
	private AccountCheckingInvestOrderMapper accountCheckingInvestOrderMapper;

	@Autowired
	private AccountCheckingFundTransferOrderMapper accountCheckingFundTransferOrderMapper;

	@Autowired
	private AccountCheckingActivityOrderMapper accountCheckingActivityOrderMapper;
	
	@Autowired
	private AccountCheckingTransStatMapperExt accountCheckingTransStatMapperExt;
	@Autowired
	private SnowflakeIdWorker snowflakeIdWorker;
	@Reference(version = "1.0.0")
	private CreditorTransferConfirmDubboService creditorTransferConfirmDubboService;

    @Reference(version = "1.0.0")
    private RefundOrderDetailBizDubboService refundOrderDetailBizDubboService ;

	public List<AccountCheckingTransation> load(Long checkRecordId, int page, int pageSize) {
		// shardingjdbc 强制走主库
		if (!HintManagerHolder.isMasterRouteOnly()) {
            HintManagerHolder.clear();
            HintManager hintManager = HintManager.getInstance();
            hintManager.setMasterRouteOnly();
        }
				
		log.debug("is matster route only : {}", HintManagerHolder.isMasterRouteOnly());
		
		PageHelper.startPage(page, pageSize);
		AccountCheckingTransation condition = new AccountCheckingTransation();
		condition.setCheckingRecordId(checkRecordId);
		return accountCheckingTransationMapperExt.selectBy(condition);
	}

	public AccountCheckingException check(AccountCheckingTransation transation, String checkDate) {
		if (transation == null)
			return null;

		AccountCheckingException exp = null;
		// 见上海银行对账文件格式说明V1.12.pdf 2.4 交易 文件
		// 【业务类型】：03投标、04还款、06代偿、07营销款、14分润、21平台资金划拨
		// 异常类型: 1银行有记录，平台无记录，2银行无记录，平台有记录，3银行与平台记录存在差异
		// 所属对账文件: 2交易文件

		// 比对流程：
		// 1. 根据平台流水号查找对应表获取数据；
		// 2. 比对金额(amount)和利息金额(income)，利息金额仅还款、代偿时需要比对
		switch (transation.getBusinessType()) {
		case 4: // 还款 t_tc_refund_order_detail_biz
            exp = checkRefundOrder(transation,checkDate,BusinessTypeEnum.REPAYMENT);
            break;
         case 5:
            exp = checkCreditor(transation,checkDate,BusinessTypeEnum.CREDIT_ASSIGNMENT);
			break;
		case 6: // 代偿 t_tc_refund_order_detail_biz
            exp = checkRefundOrder(transation,checkDate,BusinessTypeEnum.COMPENSATORY);
            break;
		case 9: // 还代偿款 t_tc_refund_order_detail_biz
            exp = checkRefundOrder(transation,checkDate,BusinessTypeEnum.COMPENSATORY_REPAYMENT);
            break;
		case 14: // 分润 t_ac_batch_trans_order_detail_biz ,t_tc_refund_order_detail_biz
			exp = checkTransOrderNew(transation, checkDate);
			break;
		case 7: // 营销款 t_ac_activity_order
			exp = checkPrizeOrder(transation, checkDate);
			break;
		case 21: // 用户平台资金划拨 t_ac_account_fund_transfer_order， 投资账户到借款账户
			exp = checkFundTransferOrder(transation, checkDate);
			break;
		case 32: // 集团资金划拨 t_ac_account_fund_transfer_order，集团账号之间的转账，不收手续费
			exp = checkFundTransferOrder(transation, checkDate);
			break;
		case 3: // 投标 t_ac_project_invest_custody_order AccountInvestService
			//exp = checkInvest(transation, checkDate); //所有的投标对应的是批量放款不在此处处理
			//break;
			return null;
		default: // 直接记录异常
			exp = getPlatformNoRecordException(transation, checkDate);
			break;
		}

		return exp;
	}

	private AccountCheckingException checkCreditor(AccountCheckingTransation transaction,String checkDate,BusinessTypeEnum businessTypeEnum){
		Boolean isError = Boolean.FALSE;
		AccountCheckingException accountCheckingException = new AccountCheckingException();
		List<String> errors = new ArrayList<>();
		CreditorTransferConfirmOrderDetailDTO creditorTransferConfirmOrderDetailDTO = creditorTransferConfirmDubboService.getConfirmOrderDetail(transaction.getPlatformRequestNo());
		if( null == creditorTransferConfirmOrderDetailDTO ){
			accountCheckingException.setHandleType(HandleTypeEnum.BACK_ONLY.getIndex());
			errors.add(CheckResultEnum.NO_RECORD.getName());
			return getPlatformNoRecordException(transaction,checkDate);
		}
		if( creditorTransferConfirmOrderDetailDTO.getAmountTotal().compareTo(transaction.getAmount()) !=0 ){
			accountCheckingException.setHandleType(HandleTypeEnum.BOTH_ERROR.getIndex());
			errors.add(CheckResultEnum.CREDITOR_TRANSFER_AMOUNT_NOT_EQUAL.getName());
			accountCheckingException.setPlatformRecordId(creditorTransferConfirmOrderDetailDTO.getId());
			isError = Boolean.TRUE;
		}

		if( !String.valueOf(creditorTransferConfirmOrderDetailDTO.getProjectId()).equals(transaction.getProjectNo())){
			accountCheckingException.setHandleType(HandleTypeEnum.BOTH_ERROR.getIndex());
			errors.add(CheckResultEnum.PROJECT_NO_ERROR.getName());
			accountCheckingException.setPlatformRecordId(creditorTransferConfirmOrderDetailDTO.getId());
			isError = Boolean.TRUE;
		}

		if(isError){
			accountCheckingException.setStatus(CheckExceptionStatusEnum.UNCONFIRM.getCode());
			accountCheckingException.setBusinessType(transaction.getBusinessType());
			accountCheckingException.setOrderNo(transaction.getOrderNo());
			accountCheckingException.setCheckingType((byte) 2);
			accountCheckingException.setCheckingRecordId(transaction.getCheckingRecordId());
			accountCheckingException.setCheckingDetailId(transaction.getId());
			accountCheckingException.setPlatformRecordId(creditorTransferConfirmOrderDetailDTO == null ? null : creditorTransferConfirmOrderDetailDTO.getId());
			accountCheckingException.setCreateTime(new Date());
			accountCheckingException.setBillDate(checkDate);
			accountCheckingException.setDescription(errors.toString());
			//accountCheckingTransation.setRemark(errors.toString());

            return accountCheckingException;
		}
		return null;
	}
	/**
	 * 还款对账
     * 比对 还款本金，利息
	 * @param transaction
	 * @param checkDate
	 * @return
	 */
	private AccountCheckingException checkRefundOrder(AccountCheckingTransation transaction,String checkDate,BusinessTypeEnum businessTypeEnum){
        RefundOrderDetailBizResponseDTO dto = refundOrderDetailBizDubboService.getDetailBizByRequestType(transaction.getPlatformRequestNo(),businessTypeEnum.name().toString());

		if (dto == null) {
            return getPlatformNoRecordException(transaction, checkDate);
        }
		List<String> errors = new ArrayList<String>();
		AccountCheckingException accountCheckingException = new AccountCheckingException();
        if( dto.getAmount().compareTo(transaction.getAmount()) != 0 ){
            errors.add(CheckResultEnum.TRANSACTION_AMOUNT_NOT_EQUAL.getName());
            accountCheckingException.setHandleType(HandleTypeEnum.BOTH_ERROR.getIndex());
            accountCheckingException.setPlatformRecordId(dto.getId());
			accountCheckingException.setCheckingDetailId(dto.getId());
        }
        BigDecimal localIncome = dto.getInterest().add(dto.getPenaltyFee());
        if( localIncome.compareTo(transaction.getIncome()) != 0 ){
            errors.add(CheckResultEnum.TRANSACTION_INTEREST_NOT_EQUAL.getName());
            accountCheckingException.setHandleType(HandleTypeEnum.BOTH_ERROR.getIndex());
            accountCheckingException.setPlatformRecordId(dto.getId());
			accountCheckingException.setCheckingDetailId(dto.getId());
        }
        if( !transaction.getProjectNo().equals(String.valueOf(dto.getProjectId())) ){
            errors.add(CheckResultEnum.PROJETNO_NOT_EQUAL.getName());
            accountCheckingException.setHandleType(HandleTypeEnum.BOTH_ERROR.getIndex());
            accountCheckingException.setPlatformRecordId(dto.getId());
			accountCheckingException.setCheckingDetailId(dto.getId());
        }
		return submit(transaction,accountCheckingException,dto,errors,checkDate);
	}

	/**
	 * 代偿
	 * @param transation
	 * @param checkDate
	 * @return
	 */
	private AccountCheckingException checkRefundPaymentOrder(AccountCheckingTransation transation,String checkDate){
		return null;
	}
	/**
	 * 营销款相关账单对账
	 * 
	 * @param transation
	 * @param checkDate
	 * @return
	 */
	private AccountCheckingException checkPrizeOrder(AccountCheckingTransation transation, String checkDate) {
		List<AccountCheckingActivityOrder> list = accountCheckingActivityOrderMapper
				.selectByRequestNo(transation.getPlatformRequestNo());
		
		if (list == null || list.isEmpty()) {
			return getPlatformNoRecordException(transation, checkDate);
		}

		AccountCheckingActivityOrder activityOrder = list.get(0);

		StringBuffer buf = new StringBuffer();
		boolean isTrue = true;
		// 比对字段：1. 金额；2. 状态；
		if (transation.getAmount().compareTo(activityOrder.getAmount()) != 0) {
			isTrue = false;
			buf.append("账单金额不等；");
		}
		
		if (!transation.getTargetAcSoacountId().equals(activityOrder.getAccountNo())) {
			isTrue = false;
			buf.append("账单用户不对；");
		}
		
		if (!isTrue) {
			AccountCheckingException exp = new AccountCheckingException();
			exp.setBillDate(checkDate);
			exp.setBusinessType(transation.getBusinessType());
			exp.setHandleType(HandleTypeEnum.BOTH_ERROR.getIndex()); // 1银行有记录，平台无记录
			exp.setCreateTime(new Date());
			exp.setCheckingRecordId(transation.getCheckingRecordId());
			exp.setCheckingDetailId(transation.getId());
			exp.setPlatformRecordId(activityOrder.getId());
			exp.setCheckingType((byte) 2); // 2交易文件
			exp.setDescription(buf.toString());
			exp.setStatus(CheckExceptionStatusEnum.UNCONFIRM.getCode());
			exp.setOrderNo(transation.getOrderNo());

			return exp;
		}

		return null;
	}

	/**
	 * 资金划拨相关账单对账
	 * 
	 * @param transation
	 * @param checkDate
	 * @return
	 */
	private AccountCheckingException checkFundTransferOrder(AccountCheckingTransation transation, String checkDate) {
		List<AccountCheckingFundTransferOrder> list = accountCheckingFundTransferOrderMapper
				.selectByRequestNo(transation.getPlatformRequestNo());

		if (list == null || list.isEmpty()) {
			return getPlatformNoRecordException(transation, checkDate);
		}

		AccountCheckingFundTransferOrder fundTransferOrder = list.get(0);

		StringBuffer buf = new StringBuffer();
		boolean isTrue = true;
		// 比对字段：1. 金额；2. 状态；
		if (transation.getAmount().compareTo(fundTransferOrder.getAmount()) != 0) {
			isTrue = false;
			
			buf.append("账单金额不等；");
		}
		
		if (!fundTransferOrder.getPayAccountNo().equals(transation.getSourceAccountId())
				|| !fundTransferOrder.getReceiveAccountNo().equals(transation.getTargetAcSoacountId())) {
			isTrue = false;
			
			buf.append("账单转出或转入用户编码不一致；");
		}
		
		if (!isTrue) {
			AccountCheckingException exp = new AccountCheckingException();
			exp.setBillDate(checkDate);
			exp.setBusinessType(transation.getBusinessType());
			exp.setHandleType(HandleTypeEnum.BOTH_ERROR.getIndex()); // 1银行有记录，平台无记录
			exp.setCreateTime(new Date());
			exp.setCheckingRecordId(transation.getCheckingRecordId());
			exp.setCheckingDetailId(transation.getId());
			exp.setPlatformRecordId(fundTransferOrder.getId());
			exp.setCheckingType((byte) 2); // 2交易文件
			exp.setDescription(buf.toString());
			exp.setStatus(CheckExceptionStatusEnum.UNCONFIRM.getCode());
			exp.setOrderNo(transation.getOrderNo());

			return exp;
		}

		return null;
	}

	/**
	 * 投标相关账单对账
	 * 
	 * @param transation
	 * @param checkDate
	 * @return
	 */
	private AccountCheckingException checkInvest(AccountCheckingTransation transation, String checkDate) {
		List<AccountCheckingInvestOrder> list = accountCheckingInvestOrderMapper
				.selectByRequestNo(transation.getPlatformRequestNo());

		if (list == null || list.isEmpty()) {
			return getPlatformNoRecordException(transation, checkDate);
		}

		AccountCheckingInvestOrder investOrder = list.get(0);

		StringBuffer buf = new StringBuffer();
		boolean isTrue = true;
		if (transation.getAmount().compareTo(investOrder.getAmount()) != 0) {
			isTrue = false;
			buf.append("账单金额不等；");
		}
		
		if (!transation.getSourceAccountId().equals(investOrder.getPlatformUserNo())) {
			isTrue = false;
			buf.append("账单用户编码不一致；");
		}
		
		if (!isTrue) {
			AccountCheckingException exp = new AccountCheckingException();
			exp.setBillDate(checkDate);
			exp.setBusinessType(transation.getBusinessType());
			exp.setHandleType(HandleTypeEnum.BOTH_ERROR.getIndex()); // 1银行有记录，平台无记录
			exp.setCreateTime(new Date());
			exp.setCheckingRecordId(transation.getCheckingRecordId());
			exp.setCheckingDetailId(transation.getId());
			exp.setPlatformRecordId(investOrder.getId());
			exp.setCheckingType((byte) 2); // 2交易文件
			exp.setDescription(buf.toString());
			exp.setStatus(CheckExceptionStatusEnum.UNCONFIRM.getCode());
			exp.setOrderNo(transation.getOrderNo());

			return exp;
		}

		return null;
	}

	private AccountCheckingException checkTransOrderNew(AccountCheckingTransation transaction, String checkDate) {

		AccountCheckingException accountCheckingException = new AccountCheckingException();
				BusinessTypeEnum businessTypeEnum = BusinessTypeEnum.PROFIT;
		RefundOrderDetailBizResponseDTO dto = refundOrderDetailBizDubboService.getDetailBizByRequestType(transaction.getPlatformRequestNo(),businessTypeEnum.name().toString());
		if (dto == null) {
			return getPlatformNoRecordException(transaction, checkDate);
		}
		List<String> errors = new ArrayList<String>();
		if( transaction.getAmount().compareTo(dto.getAmount()) != 0 ){
			errors.add(CheckResultEnum.PROFIT_AMOUNT_NOT_EQUAL.getName());
			accountCheckingException.setHandleType(HandleTypeEnum.BOTH_ERROR.getIndex());
			accountCheckingException.setPlatformRecordId(dto.getId());
		}
		return submit(transaction,accountCheckingException,dto,errors,checkDate);
	}

	private AccountCheckingException getPlatformNoRecordException(AccountCheckingTransation transation,
			String checkDate) {
		AccountCheckingException exp = new AccountCheckingException();
		exp.setBillDate(checkDate);
		exp.setBusinessType(transation.getBusinessType());
		exp.setHandleType(HandleTypeEnum.BACK_ONLY.getIndex()); // 1银行有记录，平台无记录
		exp.setCreateTime(new Date());
		exp.setCheckingRecordId(transation.getCheckingRecordId());
		exp.setCheckingDetailId(transation.getId());
		exp.setCheckingType((byte) 2); // 2交易文件
		exp.setDescription(CheckResultEnum.NO_RECORD.getName());
		exp.setStatus(CheckExceptionStatusEnum.UNCONFIRM.getCode());
		exp.setOrderNo(transation.getOrderNo());

		return exp;
	}

	public AccountCheckingTransation parse(Long checkingRecordId, String content) {
		if (content == null || "".equals(content))
			return null;

		String[] sArr = content.split(",");

		AccountCheckingTransation record = new AccountCheckingTransation();
		// 1发生时间,2平台商编,3平台请求流水号,4订单号,5业务类型,6金额,7利息金额,8币种,9发起方会员编号,10发起方平台用户编号,
		// 11接收方会员编号,12接收方平台用户编号,13标的号,14原订单号,15备注,16债权份额,17商户自定义参数
		//record.setId(snowflakeIdWorker.nextId());
		record.setTransactionTime(DateUtil.parseT(sArr[0]));
		record.setPlatformMerchantNo(sArr[1]);
		record.setPlatformRequestNo(sArr[2]);
		record.setOrderNo(sArr[3]);
		record.setBusinessType(Byte.valueOf(sArr[4]));
		record.setAmount(BigDecimal.valueOf(Double.valueOf(sArr[5])));
		record.setIncome(BigDecimal.valueOf(Double.valueOf(sArr[6])));
		record.setAmonnt("人民币");
		record.setSourceAccountNo(sArr[8]);
		record.setSourceAccountId(sArr[9]);
		record.setTargetAcSoacountNo(sArr[10]);
		record.setTargetAcSoacountId(sArr[11]);
		record.setProjectNo(sArr[12]);
		record.setOriginalOrderNo(sArr[13]);
		record.setRemark(sArr[14]);
		record.setSubscribeCredit(BigDecimal.valueOf(Double.valueOf(sArr[15])));
		if (!content.endsWith(","))
			record.setCustomDefine(sArr[16]);

		record.setStatus((byte) 1); // 1待处理
		record.setCheckingRecordId(checkingRecordId);
		record.setIsBatch((byte) 2); // 2否

		return record;
	}

	public void save(List<AccountCheckingTransation> list) {
		if (list == null || list.isEmpty())
			return;

		for (AccountCheckingTransation t : list) {
			accountCheckingTransationMapperExt.insert(t);
		}
		
//		accountCheckingTransationMapperExt.batchInsert(list);
	}

	public void deleteCheckRecord(Long checkingRecordId) {
		accountCheckingTransationMapperExt.deleteIncompleteRecord(checkingRecordId);
	}

	public void batchUpdateCheckDetailStatus(Long checkingRecordId, Byte status) {
		accountCheckingTransationMapperExt.batchUpdateCheckDetailStatus(checkingRecordId, status);
	}

	@Override
	public void extendBusiness(Long checkingRecordId) {
		//因为不经过解析入库所以不会清掉历史数据，所以需要显示删除
		accountCheckingTransStatMapperExt.deleteIncompleteRecord(checkingRecordId);
		
		// shardingjdbc 强制走主库
		if (!HintManagerHolder.isMasterRouteOnly()) {
            HintManagerHolder.clear();
            HintManager hintManager = HintManager.getInstance();
            hintManager.setMasterRouteOnly();
        }
				
		//TODO: 统计
		List<AccountCheckingTransStat> list = accountCheckingTransationMapperExt.statAccountCheckingTransation(checkingRecordId);
		
		for (AccountCheckingTransStat stat : list) {
			//如果不是投标类型且数量等于1跳过
			if (stat.getBusinessType() != BankBizTypeEnum.INVEST.getCode() && stat.getRecordCount() == 1) continue;
			
			//更新原纪录状态
			accountCheckingTransationMapperExt.updateTransationIsBatch(stat.getPlatformRequestNo());
			
			//保存统计记录
			accountCheckingTransStatMapperExt.insertSelective(stat);
		}
	}

	@Override
	public void deleteAllCheckSuccessBankOrder(Long checkingRecordId) {
		accountCheckingTransationMapperExt.deleteAllCheckSuccessBankOrder(checkingRecordId);
	}


	private AccountCheckingException submit(AccountCheckingTransation accountCheckingTransation,
											AccountCheckingException accountCheckingException, RefundOrderDetailBizResponseDTO refundOrderDetailBizResponseDTO, List<String> errors,
											String checkDate) {
		if (null != errors && errors.size() > 0) {
			accountCheckingException.setStatus(CheckExceptionStatusEnum.UNCONFIRM.getCode());
			accountCheckingException.setBusinessType(accountCheckingTransation.getBusinessType());
			accountCheckingException.setOrderNo(accountCheckingTransation.getOrderNo());
			accountCheckingException.setCheckingType((byte) 2);
			accountCheckingException.setCheckingRecordId(accountCheckingTransation.getCheckingRecordId());
			accountCheckingException.setCheckingDetailId(accountCheckingTransation.getId());
			accountCheckingException.setPlatformRecordId(refundOrderDetailBizResponseDTO == null ? null : refundOrderDetailBizResponseDTO.getId());
			accountCheckingException.setCreateTime(new Date());
			accountCheckingException.setBillDate(checkDate);
			accountCheckingException.setDescription(errors.toString());
			accountCheckingTransation.setRemark(errors.toString());

			return accountCheckingException;
		}
		return null;
	}

}
